package gui;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import plots.ParallelCoordinatesPlot;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PImage;
import core.College;
import core.HubwayStation;
import core.MBTAStation;
import core.Trip;


public class VisualAnalytics extends PApplet {

	// -----------------------------------------------------------------
	// Atributos
	// -----------------------------------------------------------------

	private Map<Integer, HubwayStation> hubwayStations;
	private Map<Integer, College> colleges;
	private Map<Integer, MBTAStation> mbtaStations;

	private Map<Integer, Point> pointsHubwayStations;
	private Map<Integer, Point> pointsColleges;
	private Map<Integer, Point> pointsMbtaStations;

	/**
	 * Valores maximos y minimos para latitud y longitud de la Tierra
	 */
	private float dataLatMin;
	private float dataLatMax;
	private float dataLonMin;
	private float dataLonMax;

	/**
	 * Variables para establecer el tamanio del lienzo 
	 */
	private int xSize;
	private int ySize;

	//	String dataHubwayTrips [][];
	//	String dataColleges [][];
	//	String dataHubwayStations [][];
	//	String dataMBTAStations [][];

	private int overRadiusPoints;

	private PFont fontBig;

	private int selectedHubwayStation;

	//Buttons
	private ControlButton buttonHubwayStations;
	private ControlButton buttonMBTASubway;
	private ControlButton buttonColleges;
	private ControlButton buttonAll;

	//Plots
	//	private ParallelCoordinatesPlot parallelCoordinatesPlot;

	private PImage backgroundImage;

	private ParallelCoordinatesPlot parallelCoordinatesPlotOutgoing;
	private ParallelCoordinatesPlot parallelCoordinatesPlotIncoming;

	int numOfLines;
	int[] dataIndex;
	int tripsMin;
	int tripsMax;
	int ageMin;
	int ageMax;

	public void setup() {

		xSize = displayWidth;
		ySize = displayHeight;

		// Initialize data
		hubwayStations = new HashMap<Integer, HubwayStation>();
		colleges = new HashMap<Integer, College>();
		mbtaStations = new HashMap<Integer, MBTAStation>();

		pointsHubwayStations = new HashMap<Integer, Point>();
		pointsColleges = new HashMap<Integer, Point>();
		pointsMbtaStations = new HashMap<Integer, Point>();

		fontBig = loadFont("Arial-Black-48.vlw");
		backgroundImage = loadImage("Boston_GreyScale.jpg");

		buttonHubwayStations = new ControlButton(this, xSize/2 -30 , 50, Color.BLUE.getRGB());
		buttonHubwayStations.setText("Hubway Stations", 10, ySize - 150, fontBig);
		buttonColleges = new ControlButton(this, xSize/2 -30, 100, Color.RED.getRGB());
		buttonColleges.setText("Colleges", 10, ySize - 150, fontBig);
		buttonMBTASubway = new ControlButton(this, xSize/2 -30, 150, Color.MAGENTA.getRGB());
		buttonMBTASubway.setText("MBTA Stations", 10, ySize - 150, fontBig);
		buttonAll = new ControlButton(this, xSize/2 -30, 200, Color.BLACK.getRGB());

		selectedHubwayStation = -1;


		numOfLines = 10;
		dataIndex = new int[numOfLines];
		tripsMin = Integer.MAX_VALUE;
		tripsMax = 0;
		ageMin = Integer.MAX_VALUE;
		ageMax = 0;

		//		ArrayList<Trip> 
		//		for(int i = 0; i < numOfLines; i++)
		//		{
		//			int newIndex = 0;
		//			boolean indexFound = false;
		//			do
		//			{
		//				newIndex = (int)random(trips.size());
		//				for(int j = 0; j < dataIndex.length; j++)
		//				{
		//					if(dataIndex[i] == newIndex)
		//					{
		//						indexFound = true;
		//						break;
		//					}
		//				}
		//				if(!indexFound)
		//				{
		//					dataIndex[i] = newIndex;
		//				}
		//			}
		//			while(indexFound);
		//
		//
		//			Trip trip = trips.get(dataIndex[i]);
		//			if(trip.getDuration() < tripsMin)
		//			{
		//				tripsMin = trip.getDuration();
		//			}
		//			if(trip.getDuration() > tripsMax)
		//			{
		//				tripsMax = trip.getDuration();
		//			}
		//
		//			try {
		//				Calendar c = Calendar.getInstance();
		//				c.setTime(trip.getBirth_date());
		//				int currentAge = 2013 - c.get(Calendar.YEAR);
		//				if(currentAge < ageMin)
		//				{
		//					ageMin = currentAge;
		//				}
		//				if(currentAge > ageMax)
		//				{
		//					ageMax = currentAge;
		//				}
		//			} catch (Exception e) {
		//
		//			}
		//
		//		}

		buttonAll.setSelected();
		buttonHubwayStations.setSelected();
		buttonColleges.setSelected();
		buttonMBTASubway.setSelected();

		dataLatMin = 42.2f;
		dataLatMax = 42.4f;
		dataLonMin = -71.2f;
		dataLonMax = -70.9f;

		overRadiusPoints = 5;

		size(xSize,ySize);
		smooth();
		noStroke();

		String rowsHubwayStations[] = loadStrings("Hubway_Stations_Data.csv"); //leo archivo de datos
		for (int i=1; i< rowsHubwayStations.length; i++){
			String columns [] = rowsHubwayStations[i].split(";");
			//println(data3[i][1]);
			int id = Integer.parseInt(columns[0]);
			float posLongitude = Float.parseFloat(columns[4]);
			float posLatitude = Float.parseFloat(columns[3]);
			String name = columns[2];
			String terminalName= columns[3];
			HubwayStation station = new HubwayStation(id, posLongitude, posLatitude, name, terminalName);
			hubwayStations.put(station.getId(), station);	

			float posX = map(station.getPosLongitude(), dataLonMin, dataLonMax, 0, xSize/2);
			float posY = map(station.getPosLatitude(), dataLatMin, dataLatMax, ySize, 0);

			Point p = new Point(station.getId(), (int)posX, (int)posY, Color.BLUE.getRGB(), this);
			pointsHubwayStations.put(station.getId(), p);
		}

		String rowsHubwayTrips[] = loadStrings("Hubway_Trips.csv"); //leo archivo de datos
		int corruptedData = 0;
		int missingColumns = 0;
		for (int i=1; i< rowsHubwayTrips.length; i++){
			String columns [] = rowsHubwayTrips[i].split(",");
			//println(data1[i][1]);

			if(columns.length == 12)
			{
				try {
					int id = Integer.parseInt(columns[0]);
					String startDate = columns[3];
					String endDate = columns[5];
					int duration = Integer.parseInt(columns[2]);
					String bikeNumber = columns[7];
					int subscriptionType = Trip.getSubscritionTypeFromString(columns[8]);
					int birthDate = Integer.parseInt(columns[10]);
					int gender = Trip.getGenderFromString(columns[11]);
					Trip trip = new Trip(id, startDate, endDate, duration, bikeNumber, subscriptionType, birthDate, gender);
					int startStation = Integer.parseInt(columns[4]);
					hubwayStations.get(startStation).addOutgoingTrip(trip);
					int endStation = Integer.parseInt(columns[6]);
					hubwayStations.get(endStation).addIncomingTrip(trip);
				} catch (NumberFormatException e) {
					corruptedData++;
				}
			}
			else
			{
				missingColumns++;
			}
		}

		for(Map.Entry<Integer, HubwayStation> entry: hubwayStations.entrySet())
		{
			entry.getValue().calculateMeans();
		}
		System.err.println("Corrupted data: " + corruptedData + " registers out of " + rowsHubwayTrips.length);
		System.err.println("Missing columns: " + missingColumns + " registers out of " + rowsHubwayTrips.length);

		String rowsColleges[] = loadStrings("Colleges_Data.csv"); //leo archivo de datos
		for (int i=1; i< rowsColleges.length; i++){
			String columns [] = rowsColleges[i].split(",");
			//println(data2[i][1]);
			int id = Integer.parseInt(columns[0]);
			float posLongitude = Float.parseFloat(columns[2]);
			float posLatitude = Float.parseFloat(columns[1]);
			String name = columns[3];
			College college = new College(id, posLongitude, posLatitude, name);
			colleges.put(college.getId(), college);

			float posX = map(college.getPosLongitude(), dataLonMin, dataLonMax, 0, xSize/2);
			float posY = map(college.getPosLatitude(), dataLatMin, dataLatMax, ySize, 0);
			Point p = new Point(college.getId(), (int)posX, (int)posY, Color.RED.getRGB(), this);
			pointsColleges.put(college.getId(), p);
		}

		String rowsMBTAStations[] = loadStrings("MBTA_Subway_Stations_Data.csv"); //leo archivo de datos
		for (int i=1; i< rowsMBTAStations.length; i++){
			String columns [] = rowsMBTAStations[i].split(";");
			//println(data4[i][1]);

			int id = Integer.parseInt(columns[0]);
			float posLongitude = Float.parseFloat(columns[4]);
			float posLatitude = Float.parseFloat(columns[3]);
			String name = columns[1];
			MBTAStation mbtaStation = new MBTAStation(id, posLongitude, posLatitude, name);
			mbtaStations.put(mbtaStation.getId(), mbtaStation);

			float posX = map(mbtaStation.getPosLongitude(), dataLonMin, dataLonMax, 0, xSize/2);
			float posY = map(mbtaStation.getPosLatitude(), dataLatMin, dataLatMax, ySize, 0);
			Point p = new Point(mbtaStation.getId(), (int) posX, (int)posY, Color.MAGENTA.getRGB(), this);
			pointsMbtaStations.put(mbtaStation.getId(), p);
		}

		String[] headers = new String[3];
		headers[0] = "Duration";
		headers[1] = "Age";
		headers[2] = "Subscription type";

		double[][] minMax = new double[3][2];
		minMax[0][0] = 0;
		minMax[0][1] = 1;
		minMax[1][0] = 0;
		minMax[1][1] = 1;
		minMax[2][0] = 0;
		minMax[2][1] = 1;
		parallelCoordinatesPlotOutgoing = new ParallelCoordinatesPlot(this, headers, minMax, 1000, 500,  800, 300, 100, 100);
		parallelCoordinatesPlotIncoming = new ParallelCoordinatesPlot(this, headers, minMax, 1000, 100,  800, 300, 100, 100);
		parallelCoordinatesPlotIncoming.setLineColor(Color.GREEN.getRGB());

	}

	public void draw() {
		//Clean canvas
		background(240,240,240);
		image(backgroundImage, 0, 0, xSize / 2, ySize);

		//Create secondary "canvas"
		fill(0,0,0);
		stroke(0,0,0);
		rect(xSize/2,0,xSize, ySize);

		fill(100,100,100);
		stroke(100,100,100);
		rect(xSize/2 - 60 , 0 , 60, ySize);

		if(buttonHubwayStations.overPoint())
		{
			buttonHubwayStations.setSelected();
			buttonColleges.setUnselected();
			buttonMBTASubway.setUnselected();
			buttonAll.setUnselected();
		}

		if(buttonHubwayStations.isSelected() && !buttonAll.isSelected())
		{
			buttonHubwayStations.drawText();
		}
		buttonHubwayStations.drawButton();

		if (buttonColleges.overPoint())
		{
			buttonHubwayStations.setUnselected();
			buttonColleges.setSelected();
			buttonMBTASubway.setUnselected();
			buttonAll.setUnselected();
		}

		if(buttonColleges.isSelected() && !buttonAll.isSelected())
		{
			buttonColleges.drawText();
		}
		buttonColleges.drawButton();

		if (buttonMBTASubway.overPoint())
		{
			buttonHubwayStations.setUnselected();
			buttonColleges.setUnselected();
			buttonMBTASubway.setSelected();
			buttonAll.setUnselected();
		}

		if(buttonMBTASubway.isSelected() && !buttonAll.isSelected())
		{
			buttonMBTASubway.drawText();
		}
		buttonMBTASubway.drawButton();

		if (buttonAll.overPoint() || buttonAll.isSelected())
		{
			buttonHubwayStations.setUnselected();
			buttonColleges.setUnselected();
			buttonMBTASubway.setUnselected();
			buttonAll.setSelected();

			textFont(fontBig, 20);
			fill(0,0,0);
			text("Hubway Stations", 8, ySize - 182);
			fill(0,0,255);
			text("Hubway Stations", 10, ySize - 180);
			fill(0,0,0);
			text("Colleges", 8, ySize - 152);
			fill(255,0,0);
			text("Colleges", 10, ySize - 150);
			fill(0,0,0);
			text("MBTA Stations", 8, ySize - 122);
			fill(255,0,255);
			text("MBTA Stations", 10, ySize - 120);
			fill(0,0,0);
		}
		buttonAll.drawButton();

		textFont(fontBig, 15);
		for(Map.Entry<Integer, Point> entryColleges : pointsColleges.entrySet())
		{
			Point p = entryColleges.getValue();
			if(buttonColleges.isSelected())
			{
				if(p.overPoint())
				{
					p.setSelected();
					College college = colleges.get(p.getId());
					fill(0,0,0);
					text(college.getName(), p.getPosX() + (2 * Point.SIZE), p.getPosY() + (2 * Point.SIZE));
				}
				else
				{
					p.setUnselected();
					p.setHiglighted();
				}
			}
			else
			{
				p.setUnhighlighted();
			}
			p.drawPoint();
		}

		for(Map.Entry<Integer, Point> entryColleges : pointsHubwayStations.entrySet())
		{
			Point p = entryColleges.getValue();
			if(buttonHubwayStations.isSelected())
			{
				if(p.overPoint())
				{
					p.setSelected();
					HubwayStation hubwayStation = hubwayStations.get(p.getId());
					fill(0,0,0);
					text(hubwayStation.getName(), p.getPosX() + (2 * Point.SIZE), p.getPosY() + (2 * Point.SIZE));
					selectedHubwayStation = entryColleges.getKey();
				}
				else
				{
					p.setUnselected();
					p.setHiglighted();
				}
			}
			else
			{
				p.setUnhighlighted();
			}
			p.drawPoint();
		}

		for(Map.Entry<Integer, Point> entryColleges : pointsMbtaStations.entrySet())
		{
			Point p = entryColleges.getValue();
			if(buttonMBTASubway.isSelected())
			{
				if(p.overPoint())
				{
					p.setSelected();
					MBTAStation mStation = mbtaStations.get(p.getId());
					fill(0,0,0);
					text(mStation.getName(), p.getPosX() + (2 * Point.SIZE), p.getPosY() + (2 * Point.SIZE));
				}
				else
				{
					p.setUnselected();
					p.setHiglighted();
				}
			}
			else
			{
				p.setUnhighlighted();
			}
			p.drawPoint();
		}

		if(selectedHubwayStation != -1)
		{
			HubwayStation station = hubwayStations.get(selectedHubwayStation);
			int[] rawBirthdatesOut = station.getOutgoingBirthdates();
			int[] rawDurationsOut = station.getOutgoingDurations();
			int[] rawSubTypeOut = station.getOutgoingSubscriptionTypes();
			
			int[] rawBirthdatesIn = station.getincomingBirthdates();
			int[] rawDurationsIn = station.getIncomingDurations();
			int[] rawSubTypeIn = station.getincomingSubscriptionTypes();

			int minAge = Integer.MAX_VALUE;
			int maxAge = 0;
			int minDuration = Integer.MAX_VALUE;
			int maxDuration = 0;
			
			int minAgeIn = Integer.MAX_VALUE;
			int maxAgeIn = 0;
			int minDurationIn = Integer.MAX_VALUE;
			int maxDurationIn = 0;

			double[][] dataOut = new double[rawBirthdatesOut.length][3];

			for(int i = 0; i < rawBirthdatesOut.length; i++)
			{
				int age = 2013 - rawBirthdatesOut[i];
				dataOut[i][1] = age;
				if(age < minAge)
				{
					minAge = age;
				}
				if (age > maxAge)
				{
					maxAge = age;
				}

				int duration = rawDurationsOut[i];
				dataOut[i][0] = duration;
				if(duration < minDuration)
				{
					minDuration = duration;
				}
				if (duration > maxDuration)
				{
					maxDuration = duration;
				}

				int subType = rawSubTypeOut[i];
				dataOut[i][2] = subType;
			}
			
			double[][] dataIn = new double[rawBirthdatesIn.length][3];

			for(int i = 0; i < rawBirthdatesIn.length; i++)
			{
				int age = 2013 - rawBirthdatesIn[i];
				dataIn[i][1] = age;
				if(age < minAgeIn)
				{
					minAgeIn = age;
				}
				if (age > maxAgeIn)
				{
					maxAgeIn = age;
				}

				int duration = rawDurationsIn[i];
				dataIn[i][0] = duration;
				if(duration < minDurationIn)
				{
					minDurationIn = duration;
				}
				if (duration > maxDurationIn)
				{
					maxDurationIn = duration;
				}

				int subType = rawSubTypeIn[i];
				dataIn[i][2] = subType;
			}


			String[] headers = new String[3];
			headers[0] = "Duration\n" + minDuration + "  " + maxDuration;
			headers[1] = "Age\n" + minAge + "  " + maxAge;
			headers[2] = "Subscription type";

			double[][] minMax = new double[3][2];
			minMax[0][0] = minDuration;
			minMax[0][1] = maxDuration;
			minMax[1][0] = minAge;
			minMax[1][1] = maxAge;
			minMax[2][0] = 0;
			minMax[2][1] = 2;

			parallelCoordinatesPlotOutgoing.setNewData(headers, minMax, dataOut);
			
			double[][] minMaxIn = new double[3][2];
			minMaxIn[0][0] = minDurationIn;
			minMaxIn[0][1] = maxDurationIn;
			minMaxIn[1][0] = minAgeIn;
			minMaxIn[1][1] = maxAgeIn;
			minMaxIn[2][0] = 0;
			minMaxIn[2][1] = 2;
			parallelCoordinatesPlotIncoming.setNewData(headers, minMaxIn, dataIn);
		}
		
		
		parallelCoordinatesPlotOutgoing.setChanged();
		parallelCoordinatesPlotOutgoing.drawPlot();
		
		parallelCoordinatesPlotIncoming.setChanged();
		parallelCoordinatesPlotIncoming.drawPlot();
	}
}




